package lg.minecraft.plugin.pokemonmenu.gui;

import com.cobblemon.mod.common.api.pokemon.PokemonProperties;
import com.cobblemon.mod.common.pokemon.Pokemon;
import lg.minecraft.plugin.cobblemoncore.util.BasePokemonUtil;
import lg.minecraft.plugin.cobblemoncore.util.PokemonPropertiesArgumentType;
import lg.minecraft.plugin.pokemonmenu.LGPokemonMenu;
import lg.minecraft.plugin.pokemonmenu.PokemonPlayer;
import lg.minecraft.plugin.pokemonmenu.command.InputType;
import lg.minecraft.plugin.pokemonmenu.event.EventFactory;
import lg.minecraft.plugin.pokemonmenu.event.PokemonToItemEvent;
import lg.minecraft.plugin.pokemonmenu.handler.input.PlayerInputHandler;
import lg.minecraft.plugin.pokemonmenu.handler.input.PlayerInputManager;
import lg.minecraft.plugin.pokemonmenu.manager.PokemonPlayerManger;
import lg.minecraft.plugin.pokemonmenu.util.Position;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;

import java.util.UUID;

/**
 * @author langle__
 * @version 1.0
 */
public abstract class AbstractPokemonInventory extends PInventory implements PlayerInputHandler {

    protected final UUID targetUUID;

    protected Position select = null;
    protected Position remove = null;
    protected Position inputPokemon;

    private boolean mainHandSaved;
    private int mainHandSlot;
    private ItemStack mainHandItem;

    public AbstractPokemonInventory(UUID targetUUID, String title) {
        super(6, title);
        this.targetUUID = targetUUID;
    }

    /**
     * 处理宝可梦槽位点击事件
     *
     * @param player        玩家
     * @param click         点击类型
     * @param pokemonPlayer 宝可梦玩家对象
     * @param position      槽位位置
     */
    protected void handlePokemonSlotClick(Player player, ClickType click, PokemonPlayer pokemonPlayer, Position position) {
        Pokemon pokemon = pokemonPlayer.getPokemon(position);
        if (pokemon != null) {
            if (pokemonPlayer.isInBattle()) {
                player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0F, 0.0F);
                return;
            }
            if (!position.equals(remove) && click != ClickType.DROP) {
                remove = null;
            } else if (click == ClickType.DROP) {
                if (remove == null || !remove.equals(position)) {
                    remove = position;
                    onDrawInventory(player);
                } else if (remove.equals(position)) {
                    pokemonPlayer.removePokemon(position);
                    onDrawInventory(player);
                    player.playSound(player.getLocation(), Sound.ENTITY_SNOWBALL_THROW, 1.0F, 0.33F);
                }
                return;
            }
            if (position.equals(remove)) {
                remove = null;
                onDrawInventory(player);
                return;
            }
            if (click == ClickType.RIGHT) {
                PokemonPlayer self = PokemonPlayerManger.INSTANCE.getPokemonPlayer(player);
                self.setPreviousInventory(this);
                if (self.isEditMode() && player.hasPermission("LGPokemonMenu.edit")) {
                    new EditInventor(pokemon).openInventory(player);
                } else {
                    new PokemonInventory(pokemon).openInventory(player);
                }
                player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5F, 1F);
            } else if (click == ClickType.SHIFT_RIGHT && player.hasPermission("LGPokemonMenu.to_item")) {
                PlayerInventory playerInventory = player.getInventory();
                boolean airSlot = firstEmpty(playerInventory) >= 0;
                boolean trade = pokemon.getTradeable() || !LGPokemonMenu.getMainConfig().isDollTradeable();
                boolean maxIvs = BasePokemonUtil.countMaxIvs(pokemon) <= LGPokemonMenu.getMainConfig().getDollIvs();
                if (airSlot && trade && maxIvs) {
                    if (LGPokemonMenu.getMainConfig().getToItem() > 0 && LGPokemonMenu.getEconomy() != null) {
                        new PokemonToItemInventory(pokemonPlayer, position).openInventory(player, this);
                        player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5F, 1F);
                    } else {
                        PokemonToItemEvent event = EventFactory.callPokemonToItemEventEvent(player, pokemon);
                        if (event.isCancelled()) return;
                        ItemStack item = LGPokemonMenu.getGuiItem().getItemPokemon(pokemon);
                        addItem(playerInventory, item);
                        pokemonPlayer.removePokemon(position);
                        onDrawInventory(player);
                        player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1.0F, 1.8F);
                    }
                } else if (!airSlot) {
                    player.sendMessage(LGPokemonMenu.getMessage().getNoEmptySlot());
                    player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0F, 0.0F);
                } else if (!trade) {
                    player.sendMessage(LGPokemonMenu.getMessage().getNotTradeable());
                    player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0F, 0.0F);
                } else {
                    player.sendMessage(LGPokemonMenu.getMessage().getNotMaxIvs());
                    player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0F, 0.0F);
                }
            } else if (click == ClickType.SHIFT_LEFT) {
                Position emptyPosition = getEmptySlot(pokemonPlayer, position);
                if (emptyPosition != null) {
                    pokemonPlayer.removePokemon(position);
                    pokemonPlayer.setPokemon(emptyPosition, pokemon);
                    onDrawInventory(player);
                }
            }
        } else if (click == ClickType.RIGHT && player.hasPermission("LGPokemonMenu.edit")) {
            inputPokemon = position;
            player.closeInventory();
            player.sendMessage(LGPokemonMenu.getMessage().getInputPokemon());
            PlayerInputManager.waitForInput(player, InputType.POKEMON_PROPERTIES, this);
            player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1.0F, 1.8F);
        }
        if (click == ClickType.LEFT) {
            if (select != null) {
                if (!select.equals(position)) {
                    pokemonPlayer.swap(select, position);
                }
                select = null;
                onDrawInventory(player);
            } else if (pokemon != null) {
                select = position;
                onDrawInventory(player);
            }
        }
    }

    protected abstract Position slotToPokemonSlot(int slot);

    protected abstract Position getEmptySlot(PokemonPlayer pokemonPlayer, Position position);

    @Override
    public void onPlayerInput(Player player, String input) {
        PokemonProperties properties = PokemonPropertiesArgumentType.INSTANCE.parse(input);
        PokemonPlayerManger.INSTANCE.getPokemonPlayer(targetUUID).setPokemon(inputPokemon, properties.create());
        openInventory(player);
    }

    /**
     * 保存玩家主手物品，并在背包中清空主手槽
     */
    protected void saveAndClearMainHand(PlayerInventory playerInventory) {
        if (mainHandSaved || !LGPokemonMenu.getMainConfig().isRemoveMainHand()) return;
        mainHandSaved = true;
        mainHandSlot = playerInventory.getHeldItemSlot();
        mainHandItem = playerInventory.getItem(mainHandSlot);
        playerInventory.setItemInMainHand(null);
    }

    /**
     * 恢复之前保存的主手物品到玩家背包
     */
    protected void restoreMainHand(PlayerInventory playerInventory) {
        if (mainHandItem == null) return;
        playerInventory.setItemInMainHand(mainHandItem);
    }

    /**
     * 查找一个空槽位，但会跳过当前主手槽位（如果主手有物品）
     */
    protected int firstEmpty(PlayerInventory playerInventory) {
        for (int slot = 0; slot < 36; slot++) {
            if (slot == mainHandSlot && mainHandItem != null) continue;
            if (playerInventory.getItem(slot) == null) {
                return slot;
            }
        }
        return -1;
    }

    /**
     * 将物品放入第一个找到的空槽位（排除主手槽）
     */
    protected void addItem(PlayerInventory playerInventory, ItemStack itemStack) {
        int slot = firstEmpty(playerInventory);
        if (slot > -1) playerInventory.setItem(slot, itemStack);
    }

}
